package com.xhwl.data.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.cent.sdata.BuildingDTO;
import com.xhwl.common.dto.cent.sdata.space.ErrorSpace;
import com.xhwl.common.enums.OperationTypeEnum;
import com.xhwl.common.enums.OrganizationTypeEnum;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.*;
import com.xhwl.common.query.cent.sdata.BuildingQuery;
import com.xhwl.common.query.cent.sdata.OrganizationQuery;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.data.dao.IBuildingDao;
import com.xhwl.data.dao.IOrganizationDao;
import com.xhwl.data.mq.producer.OrganizationProducer;
import com.xhwl.data.pojo.annotation.OrganizationHandle;
import com.xhwl.data.service.IBuildingService;
import com.xhwl.data.service.IFloorService;
import com.xhwl.data.service.IOrganizationService;
import com.xhwl.data.util.AutoCodeUtils;
import com.xhwl.data.util.CodePrefixConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 9:42 2021/4/14
 */
@Service
public class BuildingServiceImpl extends ServiceImpl<IBuildingDao, Building> implements IBuildingService {

    @Autowired
    private IBuildingDao buildingDao;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private IOrganizationDao organizationDao;

    @Autowired
    private OrganizationProducer organizationProducer;

    @Autowired
    private IFloorService floorService;

    private static final Logger log = LoggerFactory.getLogger(BuildingServiceImpl.class);

    @Override
    @Transactional
    @OrganizationHandle(operationType = OperationTypeEnum.CREATE)
    public ResultJson create(BuildingDTO building) {
        this.save(building);

        // 生成编码
        if (StringUtils.isEmpty(building.getCode())) {
            String code = AutoCodeUtils.codeFormat(CodePrefixConstant.BUILDING_PREFIX, building.getId(), CodePrefixConstant.CODE_LENGTH);
            building.setCode(code);
            buildingDao.updateById(building);
        }
        Organization org = organizationService.getById(building.getOrganizationId());
        org.setCode(building.getCode());
        if (null !=building.getFunctionType()){
            org.setFunctionType(building.getFunctionType());
        }
        organizationService.update(org);
        return ResultJson.success();
    }

    @Override
    @Transactional
    public ResultJson update(BuildingDTO building) {
        Building old = buildingDao.selectById(building.getId());
        if (null == old) {
            log.error("需要更新的楼栋 {} 信息不存在", building.getId());
            return ResultJson.fail("数据错误");
        }
        Organization organization = organizationService.getById(old.getOrganizationId());
        organization.setName(building.getName());
        //保存序号到organization表
        organization.setSortField(building.getSortField());
        if (null != building.getParentId()) {
            organization.setParentId(building.getParentId());
        }
        if (StringUtils.isNotEmpty(building.getCode())) {
            organization.setCode(building.getCode());
        }
        if (null !=building.getFunctionType()){
            organization.setFunctionType(building.getFunctionType());
        }
        if (null != old.getSortField() &&!old.getSortField().equals(building.getSortField())){
            List<Organization> organizationList = organizationService.list(new OrganizationQuery().withParentId(organization.getParentId()));
            List<Integer> orgIds = organizationList.stream().filter(i->null != i.getSortField()).map(Organization::getId).collect(Collectors.toList());
            UpdateWrapper<Building> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("organization_id",orgIds);
            UpdateWrapper<Organization> organizationUpdateWrapper = new UpdateWrapper<>();
            organizationUpdateWrapper.in("id",orgIds);
            if (old.getSortField() > building.getSortField()){
                //大改小 小于等于'大'并且大于等于'小'的加1
                updateWrapper.ge("sort_field",building.getSortField());
                updateWrapper.le("sort_field",old.getSortField());
                organizationUpdateWrapper.ge("sort_field",building.getSortField());
                organizationUpdateWrapper.le("sort_field",old.getSortField());
                updateWrapper.setSql("sort_field = sort_field+1");
                organizationUpdateWrapper.setSql("sort_field = sort_field+1");
            }else {
                //小改大 大于'小'并且小于等于'大'的减1
                updateWrapper.le("sort_field",building.getSortField());
                updateWrapper.gt("sort_field",old.getSortField());
                organizationUpdateWrapper.le("sort_field",building.getSortField());
                organizationUpdateWrapper.gt("sort_field",old.getSortField());
                updateWrapper.setSql("sort_field = sort_field-1");
                organizationUpdateWrapper.setSql("sort_field = sort_field-1");
            }
            this.update(updateWrapper);
            organizationService.update(organizationUpdateWrapper);
        }
        ResultJson update = organizationService.update(organization);
        if (!update.getState()) {
            return update;
        }
        boolean b = this.updateById(building);
        return b ? ResultJson.success() : ResultJson.fail("数据错误");
    }

    @Override
    public Page page(BuildingQuery buildingQuery, Page page) {
        return buildingDao.page(page, buildingQuery);
    }

    @Override
    public List<Building> list(BuildingQuery buildingQuery) {
        return buildingDao.list(buildingQuery);
    }

    @Override
    public ResultJson delete(Integer id) {

        Building building = buildingDao.selectById(id);
        if (null == building) {
            return ResultJson.fail("数据错误");
        }
        if (organizationService.hasChild(building.getOrganizationId())) {
            return ResultJson.fail("存在下级无法删除");
        }
        Organization organization = organizationService.getById(building.getOrganizationId());
        organizationProducer.deletePush(JSON.toJSONString(Collections.singleton(organization)));
        organizationService.removeById(building.getOrganizationId());
        buildingDao.deleteById(id);
        return ResultJson.success("删除成功");
    }

    @Override
    public Building detail(Integer id) {
        return buildingDao.selectById(id);
    }

    @Override
    public Building detailByCode(String code) {
        return buildingDao.selectOne(new QueryWrapper<Building>().eq("code", code));
    }

    @Override
    @Transactional
    public ResultJson batchCreate(List<BuildingDTO> buildingDTOS) {
        if (buildingDTOS.isEmpty()) {
            return ResultJson.success();
        }
        List<Building> buildings = new ArrayList<>(buildingDTOS.size());
        IBuildingService bean = applicationContext.getBean(IBuildingService.class);
        for (BuildingDTO buildingDTOS1 : buildingDTOS) {
            bean.create(buildingDTOS1);
            buildings.add(buildingDTOS1);
        }
        return ResultJson.success("操作成功", buildings);
    }

    /**
     * todo 1 修改组织为批量创建 2 修改编码批量自动生成
     *
     * @param buildingDTOS
     * @return
     */
    @Override
    public ResultJson batchCreateFaster(List<BuildingDTO> buildingDTOS) {
        if (CollectionUtils.isEmpty(buildingDTOS)) {
            return ResultJson.fail("无效的数据");
        }

        List<ErrorSpace> errors = new ArrayList<>();
        // 数据处理 1 分组 2 校验
        Set<Integer> collect = buildingDTOS.stream().map(i -> i.getParentId()).collect(Collectors.toSet());
        Map<Integer, List<BuildingDTO>> parentAndChildMap = new HashMap<>();
        for (Integer i : collect) {
            parentAndChildMap.put(i, buildingDTOS.stream().filter(j -> i.equals(j.getParentId())).collect(Collectors.toList()));
        }
        for (Map.Entry<Integer, List<BuildingDTO>> entry : parentAndChildMap.entrySet()) {
            Integer parentId = entry.getKey();
            Organization organization = organizationDao.selectById(parentId);

            // 上级信息校验
            if (null == organization) {
                for (BuildingDTO buildingDTO : entry.getValue()) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("上级信息不存在");
                    errorSpace.setObj(buildingDTO);
                    errors.add(errorSpace);
                }
                continue;
            }

            // 名称校验
            List<BuildingDTO> value = entry.getValue();
            Map<String, BuildingDTO> map = new HashMap<>();
            Map<String, BuildingDTO> buildingDB = new HashMap<>();
            QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
            organizationQueryWrapper.select("name");
            organizationQueryWrapper.eq("parent_id", entry.getKey());
            List<Organization> buildingOrg = organizationDao.selectList(organizationQueryWrapper);
            if (!buildingOrg.isEmpty()) {
                for (Organization room : buildingOrg) {
                    buildingDB.put(room.getName(), null);
                }
            }
            for (BuildingDTO buildingDTO : value) {
                if (buildingDB.containsKey(buildingDTO.getName()) || map.containsKey(buildingDTO.getName())) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("名称重复");
                    errorSpace.setObj(buildingDTO);
                    errors.add(errorSpace);
                } else {
                    map.put(buildingDTO.getName(), buildingDTO);
                }
            }
            List<Building> correctList = new ArrayList<>();
            for (Map.Entry<String, BuildingDTO> entry1 : map.entrySet()) {
                correctList.add(entry1.getValue());
            }

            // code 校验
            Map<String, BuildingDTO> codeMap = new HashMap<>();
            Map<String, Object> codeMapDB = new HashMap<>();
            // 这里仅校验同一个项目下的编码重复
            QueryWrapper<Organization> organizationQueryWrapper1 = new QueryWrapper<>();
            organizationQueryWrapper1.select("code");
            organizationQueryWrapper1.eq("project_id", organization.getProjectId());
            organizationQueryWrapper1.eq("type", OrganizationTypeEnum.ROOM.id);
            List<Organization> organizations1 = organizationDao.selectList(organizationQueryWrapper1);
            if (!organizations1.isEmpty()) {
                codeMapDB = organizations1.stream().filter(i -> org.apache.commons.lang3.StringUtils.isNotEmpty(i.getCode())).collect(Collectors.toMap(Organization::getCode, Organization::getCode));
            }
            for (BuildingDTO buildingDTO : value) {
                if (!StringUtils.isEmpty(buildingDTO.getCode()) && (codeMapDB.containsKey(buildingDTO.getCode()) || codeMap.containsKey(buildingDTO.getCode()))) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("编码重复");
                    errorSpace.setObj(buildingDTO);
                    errors.add(errorSpace);
                } else {
                    codeMap.put(buildingDTO.getName(), buildingDTO);
                }
            }
            correctList = correctList.stream().filter(i -> codeMap.containsKey(i.getName())).collect(Collectors.toList());

            if (correctList.isEmpty()) {
                log.info("校验后没有合适的数据");
                continue;
            }
            try {
                this.saveBatch(correctList);
            } catch (Exception e) {
                log.error("批量保存房间失败 {}", e.getMessage());
                for (Building building : correctList) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("上级信息不存在");
                    errorSpace.setObj(building);
                    errors.add(errorSpace);
                }
                continue;
            }
            // 保存组织信息
            List<Organization> organizations = new ArrayList<>();
            for (Building building : correctList) {
                Organization organization1 = new Organization();
                organization1.setName(building.getName());
                organization1.setParentId(building.getParentId());
                if (StringUtils.isEmpty(building.getCode())) {
                    String code = AutoCodeUtils.codeFormat(CodePrefixConstant.BUILDING_PREFIX, building.getId(), CodePrefixConstant.CODE_LENGTH);
                    building.setCode(code);
                }
                organization1.setSortField(building.getSortField());
                organization1.setCode(building.getCode());
                organization1.setType(OrganizationTypeEnum.BUILDING.id.intValue());
                organization1.setLevel(organization.getLevel() + 1);
                organization1.setIndustryId(organization.getIndustryId());
                organization1.setEnterpriseId(organization.getEnterpriseId());
                if (null != organization.getProjectId()) {
                    organization1.setProjectId(organization.getProjectId());
                }
                organizations.add(organization1);
            }
            organizationService.saveBatch(organizations);

            // 统一分组下名称不会重复
            Map<String, Integer> collect1 = organizations.stream().collect(Collectors.toMap(Organization::getName, Organization::getId));

            for (Building building : correctList) {
                building.setOrganizationId(collect1.get(building.getName()));
            }
            this.updateBatchById(correctList);
        }
        return ResultJson.success(errors);
    }

    @Override
    public String getCurrentCode() {
        return UUID.randomUUID().toString();
    }

    /**
     * 通过楼栋code进行模糊查询,南飞鸿酆泽主数据同步专属
     */
    @Override
    public List<Building> getNFHBuilding() {
        QueryWrapper<Building> wrapper = new QueryWrapper<Building>().likeRight("code", "nfh-");
        return getBaseMapper().selectList(wrapper);
    }


    @Override
    public List findSpace(Account account, String typeCode) {
        if (null == account.getId() || StringUtils.isEmpty(typeCode)) {
            return Collections.EMPTY_LIST;
        }
        if (typeCode.equals("floor")) {
            return floorService.findByAccount(account);
        }
        return Collections.EMPTY_LIST;
    }

    @Override
    public ResultJson refreshSort(BuildingQuery buildingQuery) {
        List<Building> buildings = this.list(buildingQuery);
        List<Organization> organizationList = organizationService.list(new OrganizationQuery().withIds(buildings.stream().map(Building::getOrganizationId).collect(Collectors.toList())));
        organizationList = organizationList.stream().distinct().collect(Collectors.toList());
        Map<Integer,Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, Function.identity()));
//        List<List<Area>> parts = Lists.partition(areas, 500);
        for (int i = 0; i < buildings.size(); i++) {
            buildings.get(i).setSortField(i+1);
            JSONObject jsonObject = JSONObject.parseObject(buildings.get(i).getExpand());
            if (null != jsonObject){
                jsonObject.put("sortField",i+1);
                buildings.get(i).setExpand(jsonObject.toJSONString());
            }
            organizationMap.get(buildings.get(i).getOrganizationId()).setSortField(i+1);
        }
        this.updateBatchById(buildings);
        organizationService.updateBatchById(organizationMap.values());
        return ResultJson.success("刷新成功");
    }
}
